<template>
  <view class="play-list-box">
    <view class="pad-20">
      <uni-nav-bar :statusBar="true" :border="false" left-icon="back" background-color="transparent"
        @clickLeft="clickLeft" :rightWidth="120">
        <view class="text-center w-100 nav-title">
          <view class="font-16 font-500 col-000-8">
            播放列表
          </view>
        </view>
        <template v-slot:right>
          <view class="flex flex-center-center">
            <view class="play-type" @click="changePlayType">
              <image class="w-100" :src="playbackModeIcon" mode="widthFix"></image>
            </view>
            <view class="play-clear" @click="doClearAll">
              <image class="w-100" src="/static/images/clear.png" mode="widthFix"></image>
            </view>
          </view>
        </template>
      </uni-nav-bar>
      <view class="list-box m-t-40" ref="ELtableList">
        <view class="item" v-for="(item, index) in list" :key="index" @click="handleItemClick(item)">
          <view class="left">
            <view class="img-box flex-center-center" :class="{ on: isItemPlaying(item) }">
              <image class="img" :src="item.preview_image" mode="widthFix"></image>
              <view class="play-status" v-if="isItemPlaying(item)">
                <view class="line"></view>
                <view class="line"></view>
              </view>
            </view>
            <view class="">
              <view class="font-16 font-500 col-000-8">
                {{ item.pattern_name }}
              </view>
              <view class="time font-11 col-000-4 m-t-4">
                {{ formatTime(item.duration) }}
              </view>
            </view>
          </view>
          <view class="right">
            <view class="play-type font-11 col-fff flex-center-center" v-if="isItemPlaying(item)">
              播放中
            </view>
            <view class="clear" @click.stop="doClear(item.pattern_id, index)">
              <uni-icons color="rgba(0,0,0,0.4)" type="closeempty" size="20"></uni-icons>
            </view>
            <view class="sort">
              <image class="w-100" src="/static/images/sort.png" mode="widthFix"></image>
            </view>
          </view>
        </view>
      </view>
    </view>
  </view>
</template>

<script>
import playlistApi from '@/api/playlist';
import deviceApi from '@/api/device.js';
import mqttApi from '@/api/my-mqtt.js';
import deviceStatusMixin from '@/mixins/deviceStatusMixin.js';
import deviceStore from '@/store/deviceStore.js';
import Sortable from 'sortablejs';
import { formatTime } from '@/common/utils.js';

export default {
  mixins: [deviceStatusMixin],
  
  data() {
    return {
      deviceSn: '', // 设备序列号
      list: [],
			currentPatternId: '', // 该设备当前播放id
			currentPatternFileName: '', // 当前播放的图案文件名
      playType: '0', // ：0-顺序播放，1-随机播放，2-单曲循环
      // 播放模式: 'sequential'(顺序), 'random'(随机), 'single_loop'(单曲循环)
      playbackMode: 'sequential',
      sortableInstance: null // Sortable实例引用
    }
  },
  
  computed: {
    // 获取播放模式图标
    playbackModeIcon() {
      switch (this.playbackMode) {
        case 'random':
          return '/static/images/suij.png'; // 随机
        case 'sequential':
          return '/static/images/xunh.png'; // 顺序
        case 'single_loop':
          return '/static/images/xunh.png'; // 单曲循环(暂时用顺序图标)
        default:
          return '/static/images/xunh.png';
      }
    }
  },
  
  mounted() {
    // 延迟初始化拖拽,确保DOM完全渲染
    setTimeout(() => {
      this.rowDropList();
    }, 300);
  },
  onPullDownRefresh() {
  	this.getList()
  	setTimeout(function() {
  		uni.stopPullDownRefresh();
  	}, 1000);
  },
  onLoad(option) {
    const sn = option?.sn || '';
    
    if (sn) {
      // 使用传递的设备SN参数
      this.deviceSn = sn;
      console.log(`[PLAYLIST] 使用传递的设备SN: ${this.deviceSn}`);
      
      // 延迟执行，确保组件完全初始化
      this.$nextTick(async () => {
        // 主动请求设备当前状态，确保播放列表数据是最新的
        console.log(`[PLAYLIST] 主动请求设备 ${this.deviceSn} 播放列表数据`);
        // 这里可以添加主动请求播放列表的逻辑
        // await mqttApi.getPlaylist(this.deviceSn);
        
        // 从 deviceStore 获取播放模式
        const playbackMode = deviceStore.getPlaybackMode(this.deviceSn);
        if (playbackMode) {
          this.playbackMode = playbackMode;
          console.log(`[PLAYLIST] 从缓存获取播放模式: ${playbackMode}`);
        }
        
        this.getList();
      });
    } else {
      console.error('[PLAYLIST] 缺少设备SN参数');
      uni.showToast({
        title: '缺少设备参数',
        icon: 'none'
      });
    }
  },

  created() {
    // created 钩子中不再获取参数
  },
  
  beforeDestroy() {
    // 销毁Sortable实例，防止内存泄漏
    if (this.sortableInstance) {
      this.sortableInstance.destroy();
      this.sortableInstance = null;
      console.log('[PLAYLIST] 拖拽实例已销毁');
    }
  },

  methods: {
    formatTime,
    
		/**
		 * 判断图案是否正在播放
		 * @param {Object} item 图案对象
		 * @returns {boolean} 是否正在播放
		 */
		isItemPlaying(item) {
			// 从 deviceStore 获取当前设备状态
			const deviceStatus = deviceStore.getDeviceStatus(this.deviceSn);
			if (!deviceStatus || !deviceStatus.device) {
				return false;
			}
			
			// 检查播放状态是否为 'playing'
			const isPlaying = deviceStatus.device.playback_status === 'playing';
			if (!isPlaying) {
				return false;
			}
			
			// 检查当前播放的图案是否匹配
			const currentPattern = deviceStatus.device.current_pattern;
			return currentPattern && (
				currentPattern === item.file_name || 
				currentPattern === item.pattern_file
			);
		},

		/**
		 * 点击图案项 - 播放该图案
		 * @param {Object} item 图案对象
		 */
		async handleItemClick(item) {
			if (!this.deviceSn) {
				uni.showToast({
					title: '设备信息未加载',
					icon: 'none'
				});
				return;
			}
			
			// 获取文件名
			const fileName = item.file_name || item.pattern_file;
			if (!fileName) {
				uni.showToast({
					title: '图案文件名缺失',
					icon: 'none'
				});
				return;
			}
			
			try {
				console.log(`[PLAYLIST] 点击播放图案: ${fileName}`);
				
				// 使用 playDrawing 方法发送播放指令
				const result = await mqttApi.playDrawing(this.deviceSn, fileName);
				
				if (result) {
					uni.showToast({
						title: '播放指令已发送',
						icon: 'success',
						duration: 1500
					});
				} else {
					uni.showToast({
						title: '播放指令发送失败',
						icon: 'none'
					});
				}
			} catch (error) {
				console.error('[PLAYLIST] 播放图案失败:', error);
				uni.showToast({
					title: '播放失败',
					icon: 'none'
				});
			}
		},
    
		/**
		 * 重写设备状态变化处理方法
		 * @param {string} deviceSn 设备序列号
		 * @param {Object} status 设备状态
		 */
		onDeviceStatusChange(deviceSn, status) {
			// 只处理当前设备的状态
			if (deviceSn !== this.deviceSn) return
			
			console.log(`[PLAYLIST] 收到设备 ${deviceSn} 状态更新:`, status)
			
			// 更新播放模式
			if (status.playback && status.playback.playback_mode) {
				this.playbackMode = status.playback.playback_mode;
				console.log(`[PLAYLIST] 播放模式更新: ${this.playbackMode}`);
			}
			
			// 触发视图更新（因为 isItemPlaying 会实时从 deviceStore 读取状态）
			this.$forceUpdate();
		},

		/**
		 * 更新当前播放图案
		 * @param {string} newPatternId 新的图案ID
		 */
		updateCurrentPlayingPattern(newPatternId) {
			// 清除所有播放状态
			this.list.forEach(item => {
				this.$set(item, 'playStatus', false)
			})
			
			// 设置新的播放状态
			const newIndex = this.list.findIndex(item => item.pattern_id === newPatternId)
			if (newIndex !== -1) {
				this.$set(this.list[newIndex], 'playStatus', true)
				this.currentPatternId = newPatternId
			}
		},

		/**
		 * 根据文件名更新当前播放图案状态
		 * @param {string} fileName 文件名
		 * @param {number} playStatus 播放状态 0=停止, 1=播放, 2=暂停
		 */
		updateCurrentPlayingPatternByFileName(fileName, playStatus) {
			// 首先清除所有播放状态
			this.list.forEach(item => {
				this.$set(item, 'isPlaying', false)
				this.$set(item, 'playStatus', false)
			})
			
			// 设置新的播放状态
			const playingIndex = this.list.findIndex(item => 
				item.file_name === fileName || 
				item.pattern_file === fileName
			)
			
			if (playingIndex !== -1) {
				const isPlaying = (playStatus === 1)
				this.$set(this.list[playingIndex], 'isPlaying', isPlaying)
				this.$set(this.list[playingIndex], 'playStatus', isPlaying)
				this.$set(this.list[playingIndex], 'playbackStatus', playStatus)
				
				// 如果有对应的ID，也要保持同步
				if (this.list[playingIndex].pattern_id && this.list[playingIndex].pattern_id !== this.currentPatternId) {
					this.currentPatternId = this.list[playingIndex].pattern_id
				}
				
				console.log(`[PLAYLIST] 基于文件名更新播放状态: ${fileName}, 状态: ${playStatus}`)
			}
		},

		/**
		 * 更新图案播放进度
		 * @param {string} patternId 图案ID
		 * @param {number} progress 播放进度 (0-1)
		 * @param {number} status 播放状态
		 */
		updatePatternProgress(patternId, progress, status) {
			let index = -1;
			
			// 首先尝试通过 pattern_id 查找
			if (patternId) {
				index = this.list.findIndex(item => item.pattern_id === patternId)
			}
			
			// 如果没找到且有文件名，尝试通过文件名查找
			if (index === -1) {
				const deviceStatus = deviceStore.getDeviceStatus(this.deviceSn);
				const currentPatternFileName = deviceStatus?.device?.current_pattern;
				if (currentPatternFileName) {
					index = this.list.findIndex(item => 
						item.file_name === currentPatternFileName || 
						item.pattern_file === currentPatternFileName
					);
				}
			}
			
			if (index !== -1) {
				// 根据状态设置播放状态
				const isPlaying = status === 1 // 1=播放中
				this.$set(this.list[index], 'playStatus', isPlaying)
				this.$set(this.list[index], 'progress', progress)
				this.$set(this.list[index], 'playbackStatus', status)
				
				// 如果正在播放，更新当前播放ID
				if (isPlaying && patternId) {
					this.currentPatternId = patternId
				}
			}
		},

		/**
		 * 清除所有播放状态
		 */
		clearAllPlayingStatus() {
			this.list.forEach(item => {
				this.$set(item, 'playStatus', false)
				this.$set(item, 'progress', 0)
				this.$set(item, 'playbackStatus', 0)
			})
			this.currentPatternId = ''
			this.currentPatternFileName = ''
		},
		
    async getList() {
      console.log(`[PLAYLIST] 从数据库 API 获取播放列表数据`);
      
      if (!this.deviceSn) {
        console.warn('[PLAYLIST] 设备SN未设置');
        this.list = [];
        return;
      }
      
      try {
        // 直接调用 API 从数据库获取播放列表
        const res = await playlistApi.getPlaylist({
          deviceSn: this.deviceSn
        });
        
        console.log(`[PLAYLIST] API 返回结果:`, res);
        
        if (res.errCode !== 0) {
          throw new Error(res.errMsg || '获取播放列表失败');
        }
        
        // 获取播放列表数据（云函数返回的数据结构是 res.data，不再嵌套 playlist）
        const playlistData = res.data;
        if (!playlistData || !playlistData.patterns || playlistData.patterns.length === 0) {
          console.log(`[PLAYLIST] 设备 ${this.deviceSn} 的播放列表为空`);
          this.list = [];
          return;
        }
        
        console.log(`[PLAYLIST] 获取到 ${playlistData.patterns.length} 个图案`, playlistData.patterns);
        
        // 转换数据格式
        this.list = playlistData.patterns.map(item => ({
          pattern_id: item.pattern_id || '',
          pattern_name: item.pattern_name || item.file_name || '',
          preview_image: item.preview_image || item.thumbnail_url || '',
          description: item.description || '',
          file_name: item.file_name || '',
          pattern_file: item.pattern_file || item.file_name || '',
          duration: item.duration || item.duration || 0,
          sort_order: item.sort_order || 0,
          playStatus: false, // 默认为非播放状态
          progress: 0,
          playbackStatus: 0
        }));
        
        // 从 deviceStore 获取当前播放状态并更新列表
        const deviceStatus = deviceStore.getDeviceStatus(this.deviceSn);
        if (deviceStatus?.device?.current_pattern) {
          const currentPatternFileName = deviceStatus.device.current_pattern;
          const playbackStatus = deviceStatus.device.playback_status || 'stopped';
          const playStatus = playbackStatus === 'playing' ? 1 : 0;
          
          this.updateCurrentPlayingPatternByFileName(currentPatternFileName, playStatus);
        }
        
        console.log(`[PLAYLIST] 播放列表加载完成，共 ${this.list.length} 个图案`);
        
      } catch (error) {
        console.error('[PLAYLIST] 获取播放列表失败:', error);
        uni.showToast({
          title: error.message || '获取播放列表失败',
          icon: 'none'
        });
        this.list = [];
      }
    },
    
    clickLeft() {
      uni.navigateBack({
        delta: 1
      })
    },
    
    doClear(patternId, index) {
      if (!patternId) {
        console.warn('[PLAYLIST] 删除失败：缺少图案ID');
        uni.showToast({
          title: '删除失败：图案信息不完整',
          icon: 'none'
        });
        return;
      }
      
      playlistApi.removePattern({
        patternId: patternId,
        deviceSn: this.deviceSn
      }).then(res => {
        if (res.errCode === 0) {
          // 删除成功，从列表中移除
          this.list.splice(index, 1);
          uni.showToast({
            title: '删除成功',
            icon: 'success'
          });
          
          // 可选：重新从数据库加载列表确保同步
          // this.getList();
        } else {
          uni.showToast({
            title: res.errMsg || '删除失败',
            icon: 'none'
          });
        }
      }).catch(error => {
        console.error('[PLAYLIST] 删除图案失败:', error);
        uni.showToast({
          title: '删除失败',
          icon: 'none'
        });
      })
    },
    
    doClearAll() {
      // 这里加入确认弹窗
      let _this = this;
      uni.showModal({
        title: _this.$t('grid.clearAllTitle'),
        content: _this.$t('grid.clearAll'),
        success: (res) => {
          if (res.confirm) {
            playlistApi.clearPlaylist({
              deviceSn: _this.deviceSn
            }).then(res => {
              if (res.errCode === 0) {
                _this.list = [];
                uni.showToast({
                  title: '清空成功',
                  icon: 'success'
                });
                
                // 可选：重新从数据库加载列表确保同步
                // _this.getList();
              } else {
                uni.showToast({
                  title: res.errMsg || '清空失败',
                  icon: 'none'
                });
              }
            }).catch(error => {
              console.error('[PLAYLIST] 清空列表失败:', error);
              uni.showToast({
                title: '清空失败',
                icon: 'none'
              });
            })
          }
        }
      })
    },
    
    // 切换播放类型
    async changePlayType() {
      if (!this.deviceSn) {
        uni.showToast({
          title: '设备信息未加载',
          icon: 'error'
        });
        return;
      }

      try {
        // 循环切换播放模式: sequential -> random -> single_loop -> sequential
        let newMode = 'sequential';
        switch (this.playbackMode) {
          case 'sequential':
            newMode = 'random';
            break;
          case 'random':
            newMode = 'single_loop';
            break;
          case 'single_loop':
            newMode = 'sequential';
            break;
          default:
            newMode = 'sequential';
        }

        console.log(`[PLAYLIST] 切换播放模式: ${this.playbackMode} -> ${newMode}`);

        // 发送MQTT命令
        const result = await mqttApi.setPlaybackMode(this.deviceSn, newMode);

        if (result) {
          // 乐观更新UI
          this.playbackMode = newMode;
          
          // 显示对应的提示
          let modeName = '';
          switch (newMode) {
            case 'sequential':
              modeName = '顺序播放';
              break;
            case 'random':
              modeName = '随机播放';
              break;
            case 'single_loop':
              modeName = '单曲循环';
              break;
          }
          
          uni.showToast({
            title: modeName,
            icon: 'success'
          });
        } else {
          uni.showToast({
            title: '切换播放模式失败',
            icon: 'error'
          });
        }
      } catch (error) {
        console.error('切换播放模式异常:', error);
        uni.showToast({
          title: '操作失败，请重试',
          icon: 'error'
        });
      }
    },
    
    // 行拖拽
    rowDropList() {
      // #ifdef H5
      try {
        // 获取列表DOM元素 - H5环境直接使用$el
        let listElement = this.$refs.ELtableList;
        
        // 兼容性检查：确保DOM元素存在
        if (!listElement) {
          console.warn('[PLAYLIST] 列表DOM元素未找到，等待重试');
          // 延迟重试
          setTimeout(() => {
            this.rowDropList();
          }, 500);
          return;
        }
        
        // 如果是Vue组件实例，需要获取$el
        if (listElement.$el) {
          listElement = listElement.$el;
        }
        
        // 确保是DOM元素
        if (!(listElement instanceof HTMLElement)) {
          console.error('[PLAYLIST] 获取的不是有效的DOM元素:', listElement);
          return;
        }
        
        console.log('[PLAYLIST] 开始初始化拖拽排序功能', listElement);
        
        // 创建Sortable实例
        const sortableInstance = Sortable.create(listElement, {
          animation: 200, // 动画时间
          delay: 0, // 移动端可能需要延迟
          delayOnTouchOnly: true, // 只在触摸时延迟
          touchStartThreshold: 3, // 触摸灵敏度
          handle: '.sort', // 只能通过拖拽手柄进行拖拽
          draggable: '.item', // 可拖拽的元素
          ghostClass: 'sortable-ghost', // 拖拽时的幽灵元素样式
          chosenClass: 'sortable-chosen', // 被选中元素的样式
          dragClass: 'sortable-drag', // 正在拖拽元素的样式
          forceFallback: true, // 强制使用HTML5 DnD fallback
          fallbackClass: 'sortable-fallback', // fallback元素样式
          fallbackOnBody: true,
          swapThreshold: 0.65,
          
          // 拖拽开始
          onStart: (evt) => {
            console.log('[PLAYLIST] 开始拖拽', evt.oldIndex);
          },
          
          // 拖拽结束
          onEnd: async (evt) => {
            const oldIndex = evt.oldIndex;
            const newIndex = evt.newIndex;
            
            console.log(`[PLAYLIST] 拖拽排序: ${oldIndex} -> ${newIndex}`);
            
            // 如果位置没有变化，不处理
            if (oldIndex === newIndex) {
              console.log('[PLAYLIST] 位置未改变，跳过保存');
              return;
            }
            
            // 显示加载提示
            uni.showLoading({
              title: '保存中...',
              mask: true
            });
            
            try {
              // 更新本地列表顺序
              const movedItem = this.list.splice(oldIndex, 1)[0];
              this.list.splice(newIndex, 0, movedItem);
              
              // 更新所有图案的sort_order
              const patternOrders = this.list.map((item, index) => ({
                patternId: item.pattern_id,
                sortOrder: index
              }));
              
              console.log('[PLAYLIST] 准备保存新排序', patternOrders);
              
              // 调用API保存新的排序
              const res = await playlistApi.reorderPatterns({
                deviceSn: this.deviceSn,
                patternOrders: patternOrders
              });
              
              uni.hideLoading();
              
              if (res.errCode === 0) {
                console.log('[PLAYLIST] 排序保存成功');
                uni.showToast({
                  title: '排序已保存',
                  icon: 'success',
                  duration: 1500
                });
              } else {
                throw new Error(res.errMsg || '保存排序失败');
              }
            } catch (error) {
              console.error('[PLAYLIST] 保存排序失败:', error);
              uni.hideLoading();
              
              // 保存失败，恢复原始顺序
              const recoveredItem = this.list.splice(newIndex, 1)[0];
              this.list.splice(oldIndex, 0, recoveredItem);
              
              uni.showToast({
                title: error.message || '保存排序失败',
                icon: 'none',
                duration: 2000
              });
            }
          }
        });
        
        // 保存实例引用，便于后续销毁
        this.sortableInstance = sortableInstance;
        
        console.log('[PLAYLIST] 拖拽排序初始化完成');
      } catch (error) {
        console.error('[PLAYLIST] 初始化拖拽功能失败:', error);
        uni.showToast({
          title: '拖拽功能初始化失败',
          icon: 'none'
        });
      }
      // #endif
      
      // #ifndef H5
      console.log('[PLAYLIST] 当前平台不支持拖拽功能');
      // #endif
    }
  }
}
</script>
<style lang="scss" scoped>
.play-list-box {
  width: 100%;
  height: 100vh;
  background-image: url('/static/images/login-bg.png');
  background-size: 100% 100%;
  background-color: #fff;
  background-position: top;
  background-repeat: no-repeat;

  .list-box {
    width: 100%;

    .item {
      width: 100%;
      // height: 140rpx;
      background: #FFFFFF;
      box-shadow: 0px 0px 8rpx 0px rgba(0, 0, 0, 0.08);
      border-radius: 16rpx;
      padding: 32rpx;
      display: flex;
      align-items: center;
      justify-content: space-between;
      margin-bottom: 16rpx;
      transition: all 0.3s ease;

      .left {
        display: flex;
        align-items: center;
        justify-content: flex-start;

        .img-box {
          width: 76rpx;
          height: 76rpx;
          border-radius: 16rpx;
          background-color: rgba(0, 0, 0, 0.1);
          margin-right: 32rpx;
          position: relative;

          .img {
            width: 66rpx;
            height: 66rpx;
            border-radius: 100%;
            overflow: hidden;
          }

          .play-status {
            width: 100%;
            height: 100%;
            position: absolute;
            left: 0;
            bottom: 0;
            background: rgba(0, 0, 0, 0.3);
            border-radius: 8rpx;
            z-index: 10;
            display: flex;
            align-items: center;
            justify-content: center;

            .line {
              width: 6rpx;
              height: 30rpx;
              background-color: #fff;
              margin: 0 3rpx;
            }
          }
        }
      }

      .right {
        display: flex;
        align-items: center;
        justify-content: flex-start;

        .play-type {
          width: 106rpx;
          height: 48rpx;
          background: rgba(0, 0, 0, 0.87);
          border-radius: 24rpx;
          margin-right: 28rpx;
        }

        .clear {
          width: 32rpx;
          height: 32rpx;
          margin-right: 28rpx;
          cursor: pointer;
        }

        .sort {
          width: 40rpx;
          height: 40rpx;
          cursor: grab;
          user-select: none;
          transition: transform 0.2s ease, opacity 0.2s ease;
          
          &:active {
            cursor: grabbing;
            transform: scale(1.1);
          }
          
          &:hover {
            opacity: 0.7;
            transform: scale(1.05);
          }
        }
      }
    }
  }
  
  // Sortable 拖拽样式
  .sortable-ghost {
    opacity: 0.4 !important;
    background: linear-gradient(135deg, #f5f7fa 0%, #e8ecf1 100%) !important;
    border: 2px dashed #4A90E2 !important;
    border-radius: 16rpx !important;
    transform: scale(0.98) !important;
  }
  
  .sortable-chosen {
    opacity: 1 !important;
    background: #ffffff !important;
    box-shadow: 0 4px 12px rgba(74, 144, 226, 0.25) !important;
    border: 2px solid #4A90E2 !important;
    transform: scale(1.02) !important;
    transition: all 0.2s ease !important;
  }
  
  .sortable-drag {
    opacity: 1 !important;
    background: #ffffff !important;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18), 0 4px 12px rgba(74, 144, 226, 0.3) !important;
    transform: scale(1.05) rotate(2deg) !important;
    z-index: 9999 !important;
    border: 2px solid #4A90E2 !important;
    border-radius: 16rpx !important;
    cursor: grabbing !important;
  }
  
  .sortable-fallback {
    opacity: 1 !important;
    background: #ffffff !important;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18), 0 4px 12px rgba(74, 144, 226, 0.3) !important;
    border: 2px solid #4A90E2 !important;
    border-radius: 16rpx !important;
    cursor: grabbing !important;
  }
}

.play-type,
.play-clear {
  width: 40rpx;
  height: 40rpx;
}

.play-clear {
  margin-left: 50rpx;
}

.nav-title {
  display: flex;
  align-items: center;
  justify-content: flex-end;
}
</style>